﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Text;

namespace MiniFox.Infrastructure.Attributes
{
    /// <summary>
    /// 字段或属性值比对验证
    /// false will be return
    /// </summary>
    public class CompareValuesAttribute : ValidationAttribute
    {
        /// <summary>
        /// 要比对的字段或属性名
        /// </summary>
        public string OtherProperty { get; }
        /// <summary>
        /// 比对方式
        /// </summary>
        public CompareOperation Criteria { get; }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="otherProperty">要比对的字段或属性名</param>
        /// <param name="criteria">比对方式</param>
        public CompareValuesAttribute(string otherProperty, CompareOperation criteria)
        {
            if (otherProperty == null)
                throw new ArgumentNullException("otherProperty");

            OtherProperty = otherProperty;
            Criteria = criteria;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="value">需要验证的属性值</param>
        /// <param name="validationContext">验证上下文对象</param>
        /// <returns>验证结果</returns>
        protected override ValidationResult IsValid(object value, ValidationContext validationContext)
        {
            var otherProperty = validationContext.ObjectType.GetProperty(OtherProperty);
            
            if (otherProperty == null)//参照属性不存在
                return new ValidationResult(string.Format("未知属性: '{0}'.", OtherProperty));

            // 获取当前要验证的属性名
            var memberName = validationContext.ObjectType.GetProperties().Where(p => p.GetCustomAttributes(false).OfType<DisplayAttribute>().Any(a => a.Name == validationContext.DisplayName)).Select(p => p.Name).FirstOrDefault();
            if (memberName == null)
            {
                memberName = validationContext.DisplayName;
            }
            // 检查两个属性类型是否一致
            if (validationContext.ObjectType.GetProperty(memberName).PropertyType != otherProperty.PropertyType)
                return new ValidationResult(string.Format("'{0}' 和 '{1}' 的类型必须一致.", memberName, OtherProperty));

            // 获取参照属性值
            var other = otherProperty.GetValue(validationContext.ObjectInstance);

            // 对比验证属性与参照属性
            if (Criteria == CompareOperation.EqualTo) //相等
            {
                if (Equals(value, other))
                    return null;
            }
            else if (Criteria == CompareOperation.NotEqualTo) //不相等
            {
                if (!Equals(value, other))
                    return null;
            }
            else
            {
                // 检查验证属性与参照属性是否都为可比较对象
                if (!(value is IComparable) || !(other is IComparable))
                    return new ValidationResult(string.Format("'{0}' 和 '{1}' 必须都实现 'IComparable'接口.", validationContext.DisplayName, OtherProperty));

                // 
                var result = Comparer.Default.Compare(value, other);

                switch (Criteria)
                {
                    case CompareOperation.GreaterThan:
                        if (result > 0)
                            return null;
                        break;
                    case CompareOperation.LessThan:
                        if (result < 0)
                            return null;
                        break;
                    case CompareOperation.GreatThanOrEqualTo:
                        if (result >= 0)
                            return null;
                        break;
                    case CompareOperation.LessThanOrEqualTo:
                        if (result <= 0)
                            return null;
                        break;
                }
            }

            return new ValidationResult(ErrorMessage);
        }
    }

    /// <summary>
    /// 
    /// </summary>
    public enum CompareOperation
    {
        /// <summary>
        /// 等于
        /// </summary>
        EqualTo,
        /// <summary>
        /// 不等于
        /// </summary>
        NotEqualTo,
        /// <summary>
        /// 大于
        /// </summary>
        GreaterThan,
        /// <summary>
        /// 小于
        /// </summary>
        LessThan,
        /// <summary>
        /// 大于等于
        /// </summary>
        GreatThanOrEqualTo,
        /// <summary>
        /// 小于等于
        /// </summary>
        LessThanOrEqualTo
    }
}
